package com.eric.reporting;

import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;

import com.alibaba.fastjson.JSONObject;

/**
 * Store Analyzed Results and Prepare It for Multiple Purposes
 * 
 * @author Eric
 *
 * @param <K>
 *            Key,generally extends String
 * @param <V>
 *            Value,can be any Object
 */
public class ArrayMap<K, V> implements Cloneable {

	private final JSONObject json;

	private final Map<K, Object> map;

	boolean combineValue = true;

	public ArrayMap() {
		json = new JSONObject();
		map = new HashMap<>();
	}

	public Object clone() {
		return new ArrayMap<K, V>();
	}

	public JSONObject json() {
		return json;
	}
	
	public Map<K, Object> map() {
		return map;
	}

	/**
	 * Set If Values With Same Key Name Should Combine If Not,New Value Will
	 * Replace Old Value By Default Values Are Combined
	 * 
	 * @param ifCombine
	 *            boolean
	 */
	public void combineValue(boolean ifCombine) {
		combineValue = ifCombine;
	}

	public Object get(Object key) {
		return json.get(key);
	}

	/**
	 * Store Analyzer Results,If Key Exists Then By Default Combines The Values
	 * If Value Is Instance of java.util.List Then Add Value To It
	 * 
	 * @param k
	 *            Key
	 * @param v
	 *            Object Value
	 */
	public void put(K k, V v) {
		putJson(k, v);
		putMap(k, v);
	}

	@SuppressWarnings("unchecked")
	private void putJson(K k, V v) {
		if (json.keySet().contains(k)) {
			if (combineValue) {
				HashSet<Object> set;
				if (json.get(k) instanceof java.util.List) {
					List<Object> list = (List<Object>) json.get(k);
					set = new HashSet<>();

					for (Object o : list)
						set.add(o);

					set.add(v);
					json.put((String) k, set);
				} else if (json.get(k) instanceof java.util.Set) {
					set = (HashSet<Object>) json.get(k);
					set.add(v);
					json.put((String) k, set);
				} else {
					set = new HashSet<>();
					set.add(json.get(k));
					set.add(v);
					json.put((String) k, set);
				}
			}
		} else {
			json.put((String) k, v);
		}
	}

	@SuppressWarnings({ "unchecked" })
	private void putMap(K k, V v) {

		if (map.keySet().contains(k)) {
			if (combineValue) {
				HashSet<Object> set;
				if (map.get(k) instanceof java.util.List) {
					List<Object> list = (List<Object>) map.get(k);
					set = new HashSet<>();

					for (Object o : list)
						set.add(o);

					set.add(v);
					map.put(k, set);
				} else if (map.get(k) instanceof java.util.Set) {
					set = (HashSet<Object>) map.get(k);
					set.add(v);
					map.put(k, set);
				} else {
					set = new HashSet<>();
					set.add(map.get(k));
					set.add(v);
					map.put(k, set);
				}
			}
		} else {
			map.put(k, v);
		}

	}

	public String toString() {
		return json.toJSONString();
	}
}
